package com.nowcoder.topic.dp.middle;

/**
 * NC166 连续子数组的最大和(二)
 * @author d3y1
 */
public class NC166{
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     *
     * @param array int整型一维数组
     * @return int整型一维数组
     */
    public int[] FindGreatestSumOfSubArray (int[] array) {
//        return solution1(array);
        return solution2(array);
//        return solution3(array);
    }

    /**
     * 前缀和 + 滑动窗口
     *
     * 超时!
     *
     * @param array
     * @return
     */
    private int[] solution1(int[] array){
        int len = array.length;

        int[] dp = new int[len+1];

        for(int i=1; i<=len; i++){
            dp[i] = dp[i-1] + array[i-1];
        }

        int max = Integer.MIN_VALUE;
        int left=0,right=len,sum;
        for(int gap=len; gap>0; gap--){
            for(int j=0; j+gap<=len; j++){
                sum = dp[j+gap] - dp[j];
                if(sum > max){
                    max = sum;
                    left = j;
                    right = j+gap;
                }
            }
        }

        int[] result = new int[right-left];
        for(int i=left; i<right; i++){
            result[i-left] = array[i];
        }
        // for(int i=0,j=left; j<right; i++,j++){
        //     result[i] = array[j];
        // }

        return result;
    }

    /**
     * 动态规划
     *
     * dp[i]表示以数组中第i个整数为结尾(必选)的最大和
     *
     *         { dp[i-1] + array[i-1]  , dp[i-1] >= 0
     * dp[i] = {
     *         { array[i-1]            , dp[i-1] < 0
     *
     * @param array
     * @return
     */
    private int[] solution2(int[] array){
        int len = array.length;

        int[] dp = new int[len+1];

        int index=1,width = 0;
        int maxSum = Integer.MIN_VALUE;
        int lastWidth = Integer.MIN_VALUE;
        for(int i=1; i<=len; i++){
            if(dp[i-1] >= 0){
                dp[i] = dp[i-1] + array[i-1];
                width++;
            }else{
                dp[i] = array[i-1];
                width = 1;
            }

            // 最大和更大
            if(dp[i] > maxSum){
                maxSum = dp[i];
                index = i;
                lastWidth = width;
            }
            // 最大和相同 且 长度更长
            else if(dp[i]==maxSum && width>lastWidth){
                index = i;
                lastWidth = width;
            }
        }

        int[] result = new int[lastWidth];
        for(int i=0,j=index-lastWidth; j<index; i++,j++){
            result[i] = array[j];
        }

        return result;
    }

    /**
     * 动态规划: 空间压缩
     *
     * pre 表示以数组中上一整数为结尾的最大和
     * curr表示以数组中当前整数为结尾的最大和
     *
     *        { pre + array[i-1]  , pre >= 0
     * curr = {
     *        { array[i-1]        , pre < 0
     *
     * @param array
     * @return
     */
    private int[] solution3(int[] array){
        int len = array.length;

        int index=1,width = 0;
        int maxSum = Integer.MIN_VALUE;
        int lastWidth = Integer.MIN_VALUE;
        int pre=0,curr;
        for(int i=1; i<=len; i++){
            if(pre >= 0){
                curr = pre + array[i-1];
                width++;
            }else{
                curr = array[i-1];
                width = 1;
            }

            // 最大和更大
            if(curr > maxSum){
                maxSum = curr;
                index = i;
                lastWidth = width;
            }
            // 最大和相同 且 长度更长
            else if(curr==maxSum && width>lastWidth){
                index = i;
                lastWidth = width;
            }

            pre = curr;
        }

        int[] result = new int[lastWidth];
        for(int i=0,j=index-lastWidth; j<index; i++,j++){
            result[i] = array[j];
        }

        return result;
    }
}